package com.sloan.community.repository;

import com.sloan.community.common.command.EditArticleCommand;
import com.sloan.community.common.dto.HotArticleDTO;
import com.sloan.community.common.query.HotArticleQuery;
import com.sloan.community.po.Article;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface ArticleRepository extends R2dbcRepository<Article, Long> {


    @Query("update t_article set view = view +1 where id = :articleId")
    Mono<Void> updateViewByArticleId(@Param("articleId") Long articleId);

    @Query("update t_article set like_count = like_count +1 where id = :articleId")
    Mono<Void> likeCount(@Param("articleId") Long articleId);

    @Query("update t_article set like_count = like_count -1 where id = :articleId and like_count > 0")
    Mono<Void> unLikeCount(@Param("articleId") Long articleId);

    @Query("""
                SELECT
                  (ta.like_count * :#{#query.likeCountWeight} 
                            + COUNT(tc.id) * :#{#query.commentWeight} 
                            + ta.share_count * :#{#query.shareCountWeight} 
                            + ta.VIEW * :#{#query.viewWeight}
                  ) * (GREATEST(0, 1 - :#{#query.decayRate} * TIMESTAMPDIFF(HOUR, ta.created_time, NOW()))) AS hot_count,
                  ta.id AS article_id,
                  ta.title AS title,
                  ta.user_id as user_id
                FROM
                  t_article ta
                LEFT JOIN t_comment tc ON ta.id = tc.article_id
                GROUP BY
                  ta.id
                ORDER BY
                  hot_count DESC
                LIMIT :#{#query.limit};
            """)
    Flux<HotArticleDTO> hotList(@Param("query") HotArticleQuery query);


    @Query("""
                UPDATE
                    t_article
                SET 
                    title = :#{#command.title},
                    first_picture = :#{#command.firstPicture},
                    commentable = :#{#command.commentable},
                    recommend = :#{#command.recommend},
                    appreciation =:#{#command.appreciation},
                    shareable = :#{#command.shareable},
                    updated_by = :#{#command.updatedBy},
                    updated_time = :#{#command.updatedTime},
                    version = version + 1 
                WHERE
                  id = :#{#command.id}
            """)
    Mono<Void> editArticle(@Param("command") EditArticleCommand command);


    @Query("""
      update 
        t_article
      set 
        shareable = !shareable,
        updated_by = :updateBy,
        updated_time = :updatedTime,
        version=version+1 
      where 
        id = :id
    """)
    Mono<Void> updateShareableById(@Param("id") Long id,@Param("updateBy") Long updateBy,@Param("updatedTime") LocalDateTime updatedTime);

    @Query("""
      update 
        t_article
      set 
        commentable = !commentable,
        updated_by = :updateBy,
        updated_time = :updatedTime,
        version=version+1 
      where 
        id = :id
    """)
    Mono<Void> updateCommentableById(@Param("id") Long id,@Param("updateBy") Long updateBy,@Param("updatedTime") LocalDateTime updatedTime);

    @Query("""
      update 
        t_article
      set 
        recommend = !recommend,
        updated_by = :updateBy,
        updated_time = :updatedTime,
        version=version+1 
      where 
        id = :id
    """)
    Mono<Void> updateRecommendById(@Param("id") Long id,@Param("updateBy") Long updateBy,@Param("updatedTime") LocalDateTime updatedTime);

    @Query("""
      update 
        t_article
      set 
        appreciation = !appreciation,
        updated_by = :updateBy,
        updated_time = :updatedTime,
        version=version+1 
      where 
        id = :id
    """)
    Mono<Void> updateAppreciationById(@Param("id") Long id,@Param("updateBy") Long updateBy,@Param("updatedTime") LocalDateTime updatedTime);

    @Query("update t_article set share_count = share_count + 1 where id =:articleId")
    Mono<Void> updateShareCountById(@Param("articleId") Long articleId);

    Flux<Article> findByIdIsIn(List<Long> articleIds, Pageable pageable);

    Mono<Long> countByIdIsIn(List<Long> articleIds);
}
